tboot: fix S3 issue for Intel Trusted Execution Technology.
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 3 Feb 2010 09:44:12 +0000 (09:44 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 3 Feb 2010 09:44:12 +0000 (09:44 +0000)
Those unmapped pages cause page fault when MACing them and finally
cause S3 failure.

Signed-off-by: Shane Wang <shane.wang@intel.com>
xen/arch/x86/smpboot.c
xen/arch/x86/tboot.c
xen/common/page_alloc.c

index 26eb1e97a86b94af25fcd901b506e92b57d9a8a7..5118da3d47ebd63bea64d8e4024de1ef03178444 100644 (file)
@@ -103,7 +103,7 @@ static void map_cpu_to_logical_apicid(void);
 /* State of each CPU. */
 DEFINE_PER_CPU(int, cpu_state) = { 0 };
 
-static void *stack_base[NR_CPUS];
+void *stack_base[NR_CPUS];
 DEFINE_SPINLOCK(cpu_add_remove_lock);
 
 /*
index f02003d04008abee95e71107a9b3fb5c75967999..4a0a171a425a9867e3c502ec45e01357c6c5ebd6 100644 (file)
@@ -174,7 +174,7 @@ static void update_iommu_mac(vmac_ctx_t *ctx, uint64_t pt_maddr, int level)
 }
 
 #define is_page_in_use(page) \
-    ((page->count_info & PGC_count_mask) != 0 || page->count_info == 0)
+    (page_state_is(page, inuse) || page_state_is(page, offlining))
 
 static void update_pagetable_mac(vmac_ctx_t *ctx)
 {
@@ -236,6 +236,30 @@ static void tboot_gen_domain_integrity(const uint8_t key[TB_KEY_SIZE],
     memset(&ctx, 0, sizeof(ctx));
 }
 
+/*
+ * For stack overflow detection in debug build, a guard page is set up.
+ * This fn is used to detect whether a page is in the guarded pages for
+ * the above reason.
+ */
+static int mfn_in_guarded_stack(unsigned long mfn)
+{
+    extern void *stack_base[NR_CPUS];
+    void *p;
+    int i;
+
+    for ( i = 0; i < NR_CPUS; i++ )
+    {
+        if ( !stack_base[i] )
+            continue;
+        p = (void *)((unsigned long)stack_base[i] + STACK_SIZE -
+                     PRIMARY_STACK_SIZE - PAGE_SIZE);
+        if ( mfn == virt_to_mfn(p) )
+            return -1;
+    }
+
+    return 0;
+}
+
 static void tboot_gen_xenheap_integrity(const uint8_t key[TB_KEY_SIZE],
                                         vmac_t *mac)
 {
@@ -250,8 +274,21 @@ static void tboot_gen_xenheap_integrity(const uint8_t key[TB_KEY_SIZE],
 
         if ( !mfn_valid(mfn) )
             continue;
+        if ( (mfn << PAGE_SHIFT) < __pa(&_end) )
+            continue; /* skip Xen */
+        if ( (mfn >= PFN_DOWN(g_tboot_shared->tboot_base - 3 * PAGE_SIZE))
+             && (mfn < PFN_UP(g_tboot_shared->tboot_base
+                              + g_tboot_shared->tboot_size
+                              + 3 * PAGE_SIZE)) )
+            continue; /* skip tboot and its page tables */
+
         if ( is_page_in_use(page) && is_xen_heap_page(page) ) {
-            void *pg = mfn_to_virt(mfn);
+            void *pg;
+
+            if ( mfn_in_guarded_stack(mfn) )
+                continue; /* skip guard stack, see memguard_guard_stack() in mm.c */
+
+            pg = mfn_to_virt(mfn);
             vmac_update((uint8_t *)pg, PAGE_SIZE, &ctx);
         }
     }
@@ -266,12 +303,27 @@ static void tboot_gen_xenheap_integrity(const uint8_t key[TB_KEY_SIZE],
 static void tboot_gen_frametable_integrity(const uint8_t key[TB_KEY_SIZE],
                                            vmac_t *mac)
 {
+    unsigned int sidx, eidx, nidx;
+    unsigned int max_idx = (max_pdx + PDX_GROUP_COUNT - 1)/PDX_GROUP_COUNT;
     uint8_t nonce[16] = {};
     vmac_ctx_t ctx;
 
     vmac_set_key((uint8_t *)key, &ctx);
-    *mac = vmac((uint8_t *)frame_table,
-                PFN_UP(max_pdx * sizeof(*frame_table)), nonce, NULL, &ctx);
+    for ( sidx = 0; ; sidx = nidx )
+    {
+        eidx = find_next_zero_bit(pdx_group_valid, max_idx, sidx);
+        nidx = find_next_bit(pdx_group_valid, max_idx, eidx);
+        if ( nidx >= max_idx )
+            break;
+        vmac_update((uint8_t *)pdx_to_page(sidx * PDX_GROUP_COUNT),
+                       pdx_to_page(eidx * PDX_GROUP_COUNT)
+                       - pdx_to_page(sidx * PDX_GROUP_COUNT), &ctx);
+    }
+    vmac_update((uint8_t *)pdx_to_page(sidx * PDX_GROUP_COUNT),
+                   pdx_to_page(max_pdx - 1) + 1
+                   - pdx_to_page(sidx * PDX_GROUP_COUNT), &ctx);
+
+    *mac = vmac(NULL, 0, nonce, NULL, &ctx);
 
     printk("MAC for frametable is: 0x%08"PRIx64"\n", *mac);
 
index 7139c3d39b796832a8a3bb52d0f49cfb442d2bdf..0e1925a3bb13d1c4401c19cbda3051a4e6d6149d 100644 (file)
@@ -932,8 +932,6 @@ void init_xenheap_pages(paddr_t ps, paddr_t pe)
     if ( pe <= ps )
         return;
 
-    memguard_guard_range(maddr_to_virt(ps), pe - ps);
-
     /*
      * Yuk! Ensure there is a one-page buffer between Xen and Dom zones, to
      * prevent merging of power-of-two blocks across the zone boundary.
@@ -943,6 +941,8 @@ void init_xenheap_pages(paddr_t ps, paddr_t pe)
     if ( !is_xen_heap_mfn(paddr_to_pfn(pe)) )
         pe -= PAGE_SIZE;
 
+    memguard_guard_range(maddr_to_virt(ps), pe - ps);
+
     init_heap_pages(maddr_to_page(ps), (pe - ps) >> PAGE_SHIFT);
 }